package com.ruoyi.modbus.handler;

import com.ruoyi.modbus.domain.PlcInfo;
import net.wimpi.modbus.io.ModbusTCPTransaction;
import net.wimpi.modbus.msg.ReadMultipleRegistersRequest;
import net.wimpi.modbus.msg.ReadMultipleRegistersResponse;
import net.wimpi.modbus.net.TCPMasterConnection;
import net.wimpi.modbus.procimg.SimpleRegister;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.util.Arrays;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

//@Component
public class ModbusTcpNettyMaster implements ApplicationRunner {
    // 日志记录器，用于记录程序运行过程中的信息
    private static final Logger logger = LoggerFactory.getLogger(ModbusTcpNettyMaster.class);
    // Modbus Slave 的 IP 地址
    private static final String HOST = "127.0.0.1";
    // Modbus Slave 监听的端口号
    private static final int PORT = 502;
    // 开始读取寄存器的起始地址
    private static final int START_ADDRESS = 0;
    // 要读取的寄存器数量
    private static final int QUANTITY = 10;
    // 用于存储上一次读取的寄存器值，方便后续比较数据是否有更改
    private static int[] previousValues = new int[QUANTITY];

    // 多台PLC的IP和端口
    private static final List<PlcInfo> PLC_LIST = Arrays.asList(
            new PlcInfo("127.0.0.1", 502),
            new PlcInfo("192.168.1.11", 502)
    );

    @Override
    public void run(ApplicationArguments args) {
        logger.info("ModbusTcpNettyMaster run()方法已执行");
        for (PlcInfo plc : PLC_LIST) {
            try {
                TCPMasterConnection connection = new TCPMasterConnection(InetAddress.getByName(plc.getHost()));
                connection.setPort(plc.getPort());
                connection.connect();
                logger.info("成功连接到 Modbus Slave: {}:{}", plc.getHost(), plc.getPort());

                // 启动定时器，定时读取数据
                Timer timer = new Timer();
                timer.scheduleAtFixedRate(new ReadDataTask(connection, plc), 0, 1000);

                // 主动发送报文
                sendCustomMessage(connection,plc);
            } catch (Exception e) {
                logger.error("无法连接到 Modbus Slave {}:{} : {}", plc.getHost(), plc.getPort(), e.getMessage());
            }
        }
    }

    // 主动发送报文的方法
    public static void sendCustomMessage(TCPMasterConnection connection, PlcInfo plc) {
        try {
            // 创建读取多个寄存器的请求，这里可以根据需求修改请求内容
            ReadMultipleRegistersRequest request = new ReadMultipleRegistersRequest(START_ADDRESS, QUANTITY);
            ModbusTCPTransaction transaction = new ModbusTCPTransaction(connection);
            transaction.setRequest(request);

            // 发送前
            //logger.info("主动发送报文: {}, 事务ID: {}", request.getHexMessage(), request.getTransactionID());
            // 执行事务
            transaction.execute();
            // 执行后
            ReadMultipleRegistersResponse response = (ReadMultipleRegistersResponse) transaction.getResponse();

            // 处理响应中的寄存器值
            Object[] registerObjects = response.getRegisters();
            int[] currentValues = new int[QUANTITY];
            for (int i = 0; i < registerObjects.length; i++) {
                if (registerObjects[i] instanceof SimpleRegister) {
                    SimpleRegister register = (SimpleRegister) registerObjects[i];
                    currentValues[i] = register.getValue();
                }
            }

            // 检查数据是否有更改
            if (!Arrays.equals(previousValues, currentValues)) {
                // 按照Modbus寄存器高低位合并为float（假设每两个寄存器为一个float）
                for (int i = 0; i < currentValues.length - 1; i += 2) {
                    int high = currentValues[i];
                    int low = currentValues[i + 1];
                    int intBits = ((high & 0xFFFF) << 16) | (low & 0xFFFF);
                    float floatValue = Float.intBitsToFloat(intBits);
                    logger.info("PLC[{}:{}] 寄存器对 [{}-{}] 的值已更新为: [{} , {}] (float值: {})",plc.getHost(), plc.getPort(), i, i + 1, high, low, floatValue);
                }
                previousValues = currentValues;
            }
            //logger.info("收到自动回复报文: {}, 事务ID: {}", response.getHexMessage(), response.getTransactionID());
        } catch (Exception e) {
            logger.error("发送报文时发生异常: {}", e.getMessage());
        }
    }

    // 定时读取数据的任务类
    static class ReadDataTask extends TimerTask {
        // 存储 Modbus TCP 连接对象
        private final TCPMasterConnection connection;
        private final PlcInfo plc;

        public ReadDataTask(TCPMasterConnection connection, PlcInfo plc) {
            // 初始化连接对象
            this.connection = connection;
            this.plc = plc;
        }

        @Override
        public void run() {
            try {
                // 创建读取多个寄存器的请求，从起始地址开始读取指定数量的寄存器
                ReadMultipleRegistersRequest request = new ReadMultipleRegistersRequest(START_ADDRESS, QUANTITY);
                // 创建 Modbus TCP 事务对象
                ModbusTCPTransaction transaction = new ModbusTCPTransaction(connection);
                // 设置事务的请求对象
                transaction.setRequest(request);
                // 执行事务，发送请求并等待响应
                transaction.execute();

                // 获取响应对象
                ReadMultipleRegistersResponse response = (ReadMultipleRegistersResponse) transaction.getResponse();
                // 获取响应中的寄存器对象数组
                Object[] registerObjects = response.getRegisters();
                // 用于存储当前读取的寄存器值
                int[] currentValues = new int[QUANTITY];
                for (int i = 0; i < registerObjects.length; i++) {
                    if (registerObjects[i] instanceof SimpleRegister) {
                        // 将对象转换为 SimpleRegister 类型
                        SimpleRegister register = (SimpleRegister) registerObjects[i];
                        // 获取寄存器的十进制值
                        currentValues[i] = register.getValue();
                    }
                }
                // 检查当前读取的值和上一次读取的值是否不同
                if (!Arrays.equals(previousValues, currentValues)) {
                    // 发送前
                    logger.info("主动发送报文: {}, 事务ID: {}", request.getHexMessage(), request.getTransactionID());
                    for (int i = 0; i < currentValues.length; i+=2) {
                        int high = currentValues[i];
                    int low = currentValues[i + 1];
                    int intBits = ((high & 0xFFFF) << 16) | (low & 0xFFFF);
                    float floatValue = Float.intBitsToFloat(intBits);
                     
                        // 若数据有更改，记录更新后的寄存器值
                        logger.info("PLC[{}:{}] 寄存器对 [{}-{}] 的值已更新为: [{} , {}] (float值: {})",plc.getHost(), plc.getPort(), i, i + 1 , high, low, floatValue);
                    }
                    // 更新上一次读取的值
                    previousValues = currentValues;
                    logger.info("收到自动回复报文: {}, 事务ID: {}", response.getHexMessage(), response.getTransactionID());
                }

            } catch (Exception e) {
                // 读取数据发生异常时，记录错误信息
                logger.error("读取数据时发生异常: {}", e.getMessage());
            }
        }
    }
}